﻿using System;
using Interface_Sample_DotNet;
using System.Runtime.InteropServices;
using System.IO;
using DTGroup.Networking.Framework.Utils;
using System.Collections.Generic;
using System.Linq;
using Utility;
using System.Text;
using Model;
using SuperMap.Data;

namespace winprop
{
    public class wrapper
    {
        protected readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        WinPropAPI.WinProp_ParaMain global_parameters = new WinPropAPI.WinProp_ParaMain();
        
        public wrapper()
        {
            WinPropAPI.WinProp_Structure_Init_ParameterMain(ref global_parameters);
        }

        public void init(string projectionTypeStr, int horizontaloffset, int verticaloffset, int centrallongitude, int centrallatitude) {
            WinPropAPI.WinProp_Result NullResult = new WinPropAPI.WinProp_Result();
            logger.Info("WinPropAPI.WinProp_Result NullResult = new WinPropAPI.WinProp_Result();");
            int Error = WinPropAPI.WinProp_Structure_Init_Result(ref NullResult);
            logger.Info("int Error = WinPropAPI.WinProp_Structure_Init_Result(ref NullResult);");

            mapPrjCoordSys = new PrjCoordSys(PrjCoordSysType.UserDefined);

            SuperMap.Data.ProjectionType projectionType = StringUtil.TryParse<SuperMap.Data.ProjectionType>(projectionTypeStr == "UTM" ? "TransverseMercator" : projectionTypeStr);
            // 获取投影
            mapPrjCoordSys.Projection = new Projection(projectionType);

            // 投影参数
            PrjParameter prjParameter = new PrjParameter();
            //中央经线
            prjParameter.CentralMeridian = centrallongitude;
            //原点纬线
            prjParameter.CentralParallel = centrallatitude;
            //水平偏移
            prjParameter.FalseEasting = horizontaloffset;
            //垂直偏移量
            prjParameter.FalseNorthing = verticaloffset;
            prjParameter.ScaleFactor = projectionType == SuperMap.Data.ProjectionType.GaussKruger ? 1 : 0.9996;
            mapPrjCoordSys.PrjParameter = prjParameter;

            // 坐标系类型
            GeoCoordSys geoCoordSysObject = new GeoCoordSys(GeoCoordSysType.Wgs1984, GeoSpatialRefType.EarthLongitudeLatitude);
            mapPrjCoordSys.GeoCoordSys = geoCoordSysObject;
        }

        //cell:longitude, latitude, frequency, antheight, RSTxPower, cellname,HorizonAngleToEast, VerticalAngleToHorizontal
        public void call_winprop(string odaFilePath, string outputPath, int gridLength, int predictDistance, int floor, Res_Cell cell)
        {
            if (File.Exists(outputPath)) {
                File.Delete(outputPath);
            }

            int Error = 0;
            WinPropAPI.WinProp_ParaMain parameters = new WinPropAPI.WinProp_ParaMain();

            WinPropAPI.WinProp_Structure_Init_ParameterMain(ref parameters);

            parameters.Buildings = global_parameters.Buildings;
            
            parameters.ScenarioMode = 1; // Urban prediction
                                                //射线优势主路径
            parameters.PredictionModelUrban = 1; // Use Dominant Path Model

            parameters.SupressMessageBoxes = 1;

            parameters.UrbanLowerLeftX = cell.CellLongitude - predictDistance;
            parameters.UrbanLowerLeftY = cell.CellLatitude - predictDistance;
            parameters.UrbanUpperRightX = cell.CellLongitude + predictDistance;
            parameters.UrbanUpperRightY = cell.CellLatitude + predictDistance;

            /* Copy coordinates to prediction area of second model (not yet used) */
            parameters.RuralLowerLeftX = parameters.UrbanLowerLeftX;
            parameters.RuralLowerLeftY = parameters.UrbanLowerLeftY;
            parameters.RuralUpperRightX = parameters.UrbanUpperRightX;
            parameters.RuralUpperRightY = parameters.UrbanUpperRightY;

            /* Size of matrix with results. */
            //栅格步长
            parameters.Resolution = gridLength; // Resolution in meter

            parameters.MatrixFormat = 0;

            parameters.MatrixWidth = (uint)((parameters.UrbanUpperRightX - parameters.UrbanLowerLeftX) / parameters.Resolution + 1.0);
            parameters.MatrixHeight = (uint)((parameters.UrbanUpperRightY - parameters.UrbanLowerLeftY) / parameters.Resolution + 1.0);

            if (floor == 0)
            {
                parameters.PredictionHeight = 1.5; // Prediction height in meter
            }
            else
            {
                parameters.PredictionHeight = floor * 5;
            }
            
            parameters.BuildingsMode = 1;

            //WinPropAPI.InterfaceLoadBuildingsASCII(ref parameters.Buildings, winpropParameter.ODAFilePath);                                

            //parameters.BuildingsIndoorCoverage = 1;

            //parameters.BuildingsIndoorDecrease = 0.4;

            parameters.BuildingsIndoorCoverage = 3;  //We suggest to use the model 3
            parameters.BuildingsIndoorDecrease = 0.1;

            WinPropAPI.WinProp_Antenna DataAntenna = new WinPropAPI.WinProp_Antenna();
            Error = WinPropAPI.WinProp_Structure_Init_Antenna(ref DataAntenna);

            #region
            WinPropAPI.WinProp_Pattern AntennaPattern = new WinPropAPI.WinProp_Pattern();
            Error = WinPropAPI.WinProp_Structure_Init_Pattern(ref AntennaPattern);

            AntennaPattern.Mode = 2;
            AntennaPattern.Filename = System.AppDomain.CurrentDomain.BaseDirectory + "\\router_directional_add_14.69.apb"; //定向天线

            #endregion

            DataAntenna.Longitude_X = cell.CellLongitude;
            DataAntenna.Latitude_Y = cell.CellLatitude;
            DataAntenna.Height = cell.AntHeight; 
            DataAntenna.Power = cell.RSTxPower; //工参文件中一般设为15.2//PublicToolsKernel.DB(PublicToolsKernel.DB_Inverse(cell.RSTxPower) * 12 * 100); ; // Power in dBm
            DataAntenna.Frequency = cell.Frequency;
            DataAntenna.Name = cell.CellName;
            DataAntenna.Azimuth = cell.HorizonAngleToEast;
            DataAntenna.Downtilt = cell.VerticalAngleToHorizontal;


            DataAntenna.Pattern = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WinPropAPI.WinProp_Pattern)));

            Marshal.StructureToPtr(AntennaPattern, DataAntenna.Pattern, false);

            /* Fill "WinProp_Callback" for definition of callback functions. */
            WinPropAPI.WinProp_Callback DataCallback = new WinPropAPI.WinProp_Callback();
            WinPropAPI.ProgressCallBackPtr ProgressPointer = new WinPropAPI.ProgressCallBackPtr(OnCallbackProgress);
            WinPropAPI.MessageCallBackPtr MessagePointer = new WinPropAPI.MessageCallBackPtr(OnCallbackMessages);
            DataCallback.Percentage = ProgressPointer;
            DataCallback.Message = MessagePointer;

            WinPropAPI.WinProp_Result PropResult = new WinPropAPI.WinProp_Result();

            /* Compute prediction with the function "WinProp_Predict()". */
            //Error = WinPropAPI.OutdoorPlugIn_ComputePrediction(ref DataAntenna, ref parameters, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref DataCallback, ref PropResult, IntPtr.Zero, IntPtr.Zero);
            //Error = WinPropAPI.OutdoorPlugIn_ComputePrediction(ref DataAntenna, ref parameters, ref ParametersDPM, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref DataCallback, ref PropResult, IntPtr.Zero, IntPtr.Zero);

            parameters.AdditionalResultMode = 2;
            parameters.AdditionalResult = @"G:\桌面\output";

            WinPropAPI.WinProp_Model_DPM ParametersDPM = new WinPropAPI.WinProp_Model_DPM();
            Error = WinPropAPI.WinProp_Structure_Init_Model_DPM(ref ParametersDPM);
            ParametersDPM.DiffrLoss = 13.0;
            ParametersDPM.ExponentLOS = 2.5;
            ParametersDPM.ExponentLOSafterBP = 4.0;
            ParametersDPM.ExponentOLOS = 2.8;
            ParametersDPM.ExponentOLOSafterBP = 4.0;
            ParametersDPM.AdaptiveResolution = 0;
            ParametersDPM.Waveguiding = 0;
            ParametersDPM.BuildingLossPerMeter = 0.015;
            parameters.BreakpointFactor = 12.56;
            parameters.BuildingsMaterialsInd = 0;
            parameters.BuildingsTransmissionLoss = 10;
            parameters.Filter = 0;
            parameters.UseAntennaLimit = 0;

            Error = WinPropAPI.OutdoorPlugIn_ComputePrediction(ref DataAntenna, ref parameters, ref ParametersDPM, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref DataCallback, ref PropResult, IntPtr.Zero, IntPtr.Zero);
            if (Error != 0)
                return;
            
            Marshal.FreeHGlobal(DataAntenna.Pattern); //释放DataAntenna所分配的内存空间

            /* Allow access to result matrix and safe this to an ASCII file. */
            unsafe
            {
                /* Create triple pointer to double values of result. */
                float*** ResultMatrix = (float***)PropResult.Matrix.ToPointer();

                /* Create file for output. */
                //FileStream fs = new FileStream("PredictionResult.txt", FileMode.Create);
                FileStream fs = new FileStream(outputPath, FileMode.Create);
                StreamWriter writer = new StreamWriter(fs);

                /* Consider height 0 only. */
                int h = 0;

                /* Loop all columns. */
                for (int x = 0; x < PropResult.Columns; x++)
                {
                    /* Compute x real. */
                    double x_real = PropResult.LowerLeftX + ((double)x + 0.5) * PropResult.Resolution;

                    /* Loop all lines. */
                    for (int y = 0; y < PropResult.Lines; y++)
                    {
                        /* Compute y real. */
                        double y_real = PropResult.LowerLeftY + ((double)y + 0.5) * PropResult.Resolution;

                        /* Write value. */
                        float Value = ResultMatrix[h][x][y];

                        //// 电场强度 E[dBuV/m] = 77.21 + 20*log10(f/MHz) + RxPower[dBm]
                        //double ValueE = 77.21 + 20 * (Math.Log10(DataAntenna.Frequency)) + Value + DataAntenna.Power;
                        // Export the RxPower
                        double RxPowerValue = Value + DataAntenna.Power;

                        /* Write value. */
                        writer.WriteLine(string.Format(System.Globalization.NumberFormatInfo.InvariantInfo, "{0:F}\t{1:F}\t{2:F}", x_real, y_real, RxPowerValue));
                        //writer.WriteLine(String.Format(System.Globalization.NumberFormatInfo.InvariantInfo, "{0:F}", RxPowerValue));
                    }
                }

                /* Close everything. */
                writer.Close();
                fs.Close();
            }
            /* Free matrix for results */
            WinPropAPI.WinProp_FreeResult(ref PropResult);
        }

        public int single_cell_winprop(string outputPath, int p_city, int gridLength, int predictDistance, int maxFloor, Res_Cell cell) {
            if (Directory.Exists(outputPath))
            {
                DeleteFolder(outputPath);
            }

            Directory.CreateDirectory(outputPath);

            int Error = 0;
            WinPropAPI.WinProp_ParaMain parameters = new WinPropAPI.WinProp_ParaMain();

            WinPropAPI.WinProp_Structure_Init_ParameterMain(ref parameters);

            parameters.Buildings = global_parameters.Buildings;

            parameters.ScenarioMode = 1; // Urban prediction
                                         //射线优势主路径
            parameters.PredictionModelUrban = 1; // Use Dominant Path Model

            parameters.SupressMessageBoxes = 1;

            parameters.UrbanLowerLeftX = cell.CellLongitude - predictDistance;
            parameters.UrbanLowerLeftY = cell.CellLatitude - predictDistance;
            parameters.UrbanUpperRightX = cell.CellLongitude + predictDistance;
            parameters.UrbanUpperRightY = cell.CellLatitude + predictDistance;

            /* Copy coordinates to prediction area of second model (not yet used) */
            parameters.RuralLowerLeftX = parameters.UrbanLowerLeftX;
            parameters.RuralLowerLeftY = parameters.UrbanLowerLeftY;
            parameters.RuralUpperRightX = parameters.UrbanUpperRightX;
            parameters.RuralUpperRightY = parameters.UrbanUpperRightY;

            /* Size of matrix with results. */
            //栅格步长
            parameters.Resolution = gridLength; // Resolution in meter

            parameters.MatrixFormat = 0;

            parameters.MatrixWidth = (uint)((parameters.UrbanUpperRightX - parameters.UrbanLowerLeftX) / parameters.Resolution + 1.0);
            parameters.MatrixHeight = (uint)((parameters.UrbanUpperRightY - parameters.UrbanLowerLeftY) / parameters.Resolution + 1.0);

            

            parameters.BuildingsMode = 1;
            parameters.BuildingsIndoorCoverage = 3;  //We suggest to use the model 3
            parameters.BuildingsIndoorDecrease = 0.6;

            WinPropAPI.WinProp_Antenna DataAntenna = new WinPropAPI.WinProp_Antenna();
            Error = WinPropAPI.WinProp_Structure_Init_Antenna(ref DataAntenna);

            #region
            WinPropAPI.WinProp_Pattern AntennaPattern = new WinPropAPI.WinProp_Pattern();
            Error = WinPropAPI.WinProp_Structure_Init_Pattern(ref AntennaPattern);

            AntennaPattern.Mode = 2;
            AntennaPattern.Filename = System.AppDomain.CurrentDomain.BaseDirectory + "\\router_directional_add_14.69.apb"; //定向天线

            #endregion

            DataAntenna.Longitude_X = cell.CellLongitude;
            DataAntenna.Latitude_Y = cell.CellLatitude;
            DataAntenna.Height = cell.AntHeight;
            DataAntenna.Power = cell.RSTxPower; //工参文件中一般设为15.2//PublicToolsKernel.DB(PublicToolsKernel.DB_Inverse(cell.RSTxPower) * 12 * 100); ; // Power in dBm
            DataAntenna.Frequency = cell.Frequency;
            DataAntenna.Name = cell.CellName;
            DataAntenna.Azimuth = cell.HorizonAngleToEast;
            DataAntenna.Downtilt = cell.VerticalAngleToHorizontal;


            DataAntenna.Pattern = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WinPropAPI.WinProp_Pattern)));

            Marshal.StructureToPtr(AntennaPattern, DataAntenna.Pattern, false);

            /* Fill "WinProp_Callback" for definition of callback functions. */
            WinPropAPI.WinProp_Callback DataCallback = new WinPropAPI.WinProp_Callback();
            WinPropAPI.ProgressCallBackPtr ProgressPointer = new WinPropAPI.ProgressCallBackPtr(OnCallbackProgress);
            WinPropAPI.MessageCallBackPtr MessagePointer = new WinPropAPI.MessageCallBackPtr(OnCallbackMessages);
            DataCallback.Percentage = ProgressPointer;
            DataCallback.Message = MessagePointer;

            WinPropAPI.WinProp_Result PropResult = new WinPropAPI.WinProp_Result();

            /* Compute prediction with the function "WinProp_Predict()". */
            //Error = WinPropAPI.OutdoorPlugIn_ComputePrediction(ref DataAntenna, ref parameters, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref DataCallback, ref PropResult, IntPtr.Zero, IntPtr.Zero);
            //Error = WinPropAPI.OutdoorPlugIn_ComputePrediction(ref DataAntenna, ref parameters, ref ParametersDPM, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref DataCallback, ref PropResult, IntPtr.Zero, IntPtr.Zero);

            parameters.AdditionalResultMode = 2;
            parameters.AdditionalResult = @"G:\桌面\output";

            WinPropAPI.WinProp_Model_DPM ParametersDPM = new WinPropAPI.WinProp_Model_DPM();
            Error = WinPropAPI.WinProp_Structure_Init_Model_DPM(ref ParametersDPM);
            ParametersDPM.DiffrLoss = 13.0;
            ParametersDPM.ExponentLOS = 2.5;
            ParametersDPM.ExponentLOSafterBP = 4.0;
            ParametersDPM.ExponentOLOS = 2.8;
            ParametersDPM.ExponentOLOSafterBP = 4.0;
            ParametersDPM.AdaptiveResolution = 0;
            ParametersDPM.Waveguiding = 0;
            ParametersDPM.BuildingLossPerMeter = 0.015;
            parameters.BreakpointFactor = 12.56;
            parameters.BuildingsMaterialsInd = 0;
            parameters.BuildingsTransmissionLoss = 20.0;
            parameters.Filter = 0;
            parameters.UseAntennaLimit = 0;
            logger.Debug("start load indoor grid");
            var dicGrid = LoadIndoorGrid(p_city);
            logger.Debug("dicGrid : " + dicGrid.Count);
            for (int i = 0; i < maxFloor; i++)
            {
                logger.Debug(i);
                if (i == 0)
                {
                    parameters.PredictionHeight = 1.5; // Prediction height in meter
                }
                else
                {
                    parameters.PredictionHeight = i * 5;
                }
                logger.Debug("start prediction " + i);
                Error = WinPropAPI.OutdoorPlugIn_ComputePrediction(ref DataAntenna, ref parameters, ref ParametersDPM, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref DataCallback, ref PropResult, IntPtr.Zero, IntPtr.Zero);
                logger.Debug("end prediction " + i + "    " + Error);
                string outputFile = Path.Combine(outputPath, i + ".csv");
                /* Allow access to result matrix and safe this to an ASCII file. */
                unsafe
                {
                    /* Create triple pointer to double values of result. */
                    float*** ResultMatrix = (float***)PropResult.Matrix.ToPointer();

                    /* Create file for output. */
                    //FileStream fs = new FileStream("PredictionResult.txt", FileMode.Create);
                    FileStream fs = new FileStream(outputFile, FileMode.Create);
                    StreamWriter writer = new StreamWriter(fs);

                    /* Consider height 0 only. */
                    int h = 0;

                    /* Loop all columns. */
                    for (int x = 0; x < PropResult.Columns; x++)
                    {
                        /* Compute x real. */
                        double x_real = PropResult.LowerLeftX + ((double)x + 0.5) * PropResult.Resolution;

                        /* Loop all lines. */
                        for (int y = 0; y < PropResult.Lines; y++)
                        {
                            /* Compute y real. */
                            double y_real = PropResult.LowerLeftY + ((double)y + 0.5) * PropResult.Resolution;

                            /* Write value. */
                            float Value = ResultMatrix[h][x][y];

                            //// 电场强度 E[dBuV/m] = 77.21 + 20*log10(f/MHz) + RxPower[dBm]
                            //double ValueE = 77.21 + 20 * (Math.Log10(DataAntenna.Frequency)) + Value + DataAntenna.Power;
                            // Export the RxPower
                            double RxPowerValue = Value + DataAntenna.Power;

                            string gridid = (int)x_real / 5 + "_" + (int)y_real / 5;

                            if (dicGrid.ContainsKey(gridid))
                            {
                                dicGrid[gridid].ForEach(s => writer.WriteLine(string.Format(System.Globalization.NumberFormatInfo.InvariantInfo, "{0:F},{1:F},{2:F},{3}", x_real, y_real, RxPowerValue, s)));
                            }
                            else {
                                writer.WriteLine(string.Format(System.Globalization.NumberFormatInfo.InvariantInfo, "{0:F},{1:F},{2:F},{3}", x_real, y_real, RxPowerValue, ""));
                            }
                        }
                    }

                    /* Close everything. */
                    writer.Close();
                    fs.Close();
                }
            }
            
            Marshal.FreeHGlobal(DataAntenna.Pattern); //释放DataAntenna所分配的内存空间

            /* Free matrix for results */
            WinPropAPI.WinProp_FreeResult(ref PropResult);
            return Error;
        }
        public void DeleteFolder(string folderPath)
        {
            DirectoryInfo dir = new DirectoryInfo(folderPath);
            FileSystemInfo[] fileinfo = dir.GetFileSystemInfos();  //返回目录中所有文件和子目录
            foreach (FileSystemInfo i in fileinfo)
            {
                if (i is DirectoryInfo)            //判断是否文件夹
                {
                    DirectoryInfo subdir = new DirectoryInfo(i.FullName);
                    subdir.Delete(true);          //删除子目录和文件
                }
                else
                {
                    File.Delete(i.FullName);      //删除指定文件
                }
            }
        }
        public void load_building(string odaFilePath) {
            WinPropAPI.InterfaceLoadBuildingsASCII(ref global_parameters.Buildings, odaFilePath);
        }

        public void release_building()
        {
            WinPropAPI.InterfaceBuildingsFree(ref (global_parameters.Buildings));
        }

        /// <summary>
        /// 读取 Index 文件并获取Buildings 和buildingsAttribute文件
        /// </summary>
        /// <param name="indexPath">Index 文件路径</param>
        /// <returns>Index 的相关内容</returns>
        private List<BuildingsObject> ReadIndexFile(string indexPath)
        {
            List<BuildingsObject> buildingsObjects = new List<BuildingsObject>();
            // 获取 index 文件所在的文件夹
            string directoryPath = IOUtil.GetFileDirecotry(indexPath);
            // 读取 Index 文件内容
            ReadFileLineContent(indexPath, delegate (string readerLineContent)
            {
                if (string.IsNullOrEmpty(readerLineContent) == false)
                {
                    string[] readerLineArray = Trim(readerLineContent.Split(new char[] { ' ' }));
                    if (readerLineArray.Length == 7)
                    {
                        buildingsObjects.Add(new BuildingsObject()
                        {
                            BuildingsFilePath = Path.Combine(directoryPath, readerLineArray[0]),
                            BuildingsAttributeFilePath = Path.Combine(directoryPath, readerLineArray[1]),
                            MinX = double.Parse(readerLineArray[2]),
                            MaxX = double.Parse(readerLineArray[3]),
                            MinY = double.Parse(readerLineArray[4]),
                            MaxY = double.Parse(readerLineArray[5])
                        });
                    }
                }
            });

            return buildingsObjects;
        }
        private List<BuildingsObject> ReadAllIndexFile(string mapPath)
        {
            List<BuildingsObject> buildingsObjects = new List<BuildingsObject>();

            DirectoryInfo mapDir = new DirectoryInfo(mapPath);
            mapDir.GetFiles("index.txt", SearchOption.AllDirectories);
            var cityDirectories = mapDir.GetDirectories();
            foreach (var dir in cityDirectories)
            {
                var buildDir = dir.EnumerateDirectories("Buildvector").FirstOrDefault();
                if (buildDir != null)
                {
                    var indexFile = buildDir.GetFiles("index.txt").FirstOrDefault();
                    string directoryPath = buildDir.FullName;
                    ReadFileLineContent(indexFile.FullName, delegate (string readerLineContent)
                    {
                        if (string.IsNullOrEmpty(readerLineContent) == false)
                        {
                            string[] readerLineArray = Trim(readerLineContent.Split(new char[] { ' ' }));
                            if (readerLineArray.Length == 7)
                            {
                                buildingsObjects.Add(new BuildingsObject()
                                {
                                    BuildingsFilePath = Path.Combine(directoryPath, readerLineArray[0]),
                                    BuildingsAttributeFilePath = Path.Combine(directoryPath, readerLineArray[1]),
                                    MinX = double.Parse(readerLineArray[2]),
                                    MaxX = double.Parse(readerLineArray[3]),
                                    MinY = double.Parse(readerLineArray[4]),
                                    MaxY = double.Parse(readerLineArray[5])
                                });
                            }
                        }
                    });
                }
            }

            return buildingsObjects;
        }


        /// <summary>
        /// 读取 文件每一行内容
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="readLineContent">读取每行的内容</param>
        private static void ReadFileLineContent(string filePath, Action<string> readLineContent)
        {
            if (string.IsNullOrEmpty(filePath) == false)
            {
                if (System.IO.File.Exists(filePath))
                {
                    if (readLineContent != null)
                    {
                        Stream fileStream = new FileStream(filePath, FileMode.Open);
                        
                        using (StreamReader textReader = new StreamReader(fileStream))
                        {
                            // 文件流 读取的行数
                            string textReadLine = string.Empty;

                            while (textReadLine != null)
                            {
                                textReadLine = textReader.ReadLine();
                                if (textReadLine != null)
                                {
                                    readLineContent(textReadLine);
                                }
                            }
                        }

                        fileStream.Close();
                        fileStream.Dispose();
                    }
                }
            }
        }
        private static string[] Trim(string[] items)
        {
            List<string> returnStrs = new List<string>();

            for (int i = 0; i < items.Length; i++)
            {
                if (!string.IsNullOrEmpty(items[i]))
                {
                    returnStrs.Add(items[i].Trim());
                }
            }

            return returnStrs.ToArray();
        }

        public string BiuldODAFile(string buildVectorFilePath, string odaFolder)
        {
            if (!Directory.Exists(odaFolder)) {
                Directory.CreateDirectory(odaFolder);
            }
            string odaFilePath = GetMapODAFilePath(odaFolder);
            // 如果该目录下已经存在建筑物数据，则不需要再次生成
            if (File.Exists(odaFilePath) == false)
            {
                logger.Info("读取index文件");
                List<BuildingsObject> buildingsObjects = ReadAllIndexFile(buildVectorFilePath);

                foreach (var item in buildingsObjects)
                {
                    
                    double x = 0, y = 0;
                    using (SuperMap.Data.GeoPoint point = new SuperMap.Data.GeoPoint(Convert.ToDouble(item.MinX), Convert.ToDouble(item.MinY)))
                    {
                        CoordSysTranslatorHandler.ConvertCoordSys(point, MapPrjCoordSys, LatLonPrjCoordSys);
                        MecatorUtil.loc_to_mercator(point.X, point.Y, ref x, ref y);
                    }
                    

                    item.MinY = y;
                    item.MinX = x;
                    
                    
                    using (SuperMap.Data.GeoPoint point = new SuperMap.Data.GeoPoint(Convert.ToDouble(item.MaxX), Convert.ToDouble(item.MaxY)))
                    {
                        CoordSysTranslatorHandler.ConvertCoordSys(point, MapPrjCoordSys, LatLonPrjCoordSys);
                        MecatorUtil.loc_to_mercator(point.X, point.Y, ref x, ref y);
                    }

                    item.MaxY = y;
                    item.MaxX = x;
                }
                logger.Info("读取buildingsObjects，转换为墨卡托结束");

                if (buildingsObjects != null)
                {
                    BuildingsObject buildingsObject = new BuildingsObject()
                    {
                        MinX = buildingsObjects.Min(o => o.MinX),
                        MaxX = buildingsObjects.Max(o => o.MaxX),
                        MinY = buildingsObjects.Min(o => o.MinY),
                        MaxY = buildingsObjects.Max(o => o.MaxY)
                    };

                    Dictionary<int, BuildingVectorObject> buildingsVectorDic = new Dictionary<int, BuildingVectorObject>();
                    int orderOID = 1;
                    // 遍历 所有的Buildings 文件
                    foreach (BuildingsObject item in buildingsObjects)
                    {
                        orderOID = ReadBuildingsFileContent(buildingsVectorDic, item, orderOID, buildingsObject);
                    }
                    //logger.Info("开始输出oda文件");
                    // 输出ODA文件
                    OutODAFilePath(buildingsVectorDic, GetMapODAFilePath(odaFolder), buildingsObject);
                    buildingsVectorDic.Clear();
                    buildingsVectorDic = null;
                }
            }
            //winprop加载地图文件，ODA文件
            
            return odaFilePath;
        }

        private int OnCallbackProgress(int progress, string text)
        {
            /* TODO: Print progress (0 to 100%) to screen.. */
            return (0);
        }

        private int OnCallbackMessages(string text)
        {
            /* TODO: Print current message to screen.. */
            return (0);
        }

        private int ReadBuildingsFileContent(Dictionary<int, BuildingVectorObject> buildingVectorObjects, BuildingsObject buildingsObject, int orderOID, BuildingsObject totalBuildingsObject)
        {
            BuildingVectorObject buildVectorObject = null;
            int prevProgressValue = 0;
            int rowCount = 0;
            // 读取 文件的行数
            FileUtil.ReadFileLineContent(buildingsObject.BuildingsFilePath, delegate (string readerLineContent)
            {
                if (string.IsNullOrEmpty(readerLineContent) == false)
                {
                    rowCount++;
                }
            });

            int cusor = 1;
            int tempOrderOID = orderOID;
            // 读取 Index 文件内容
            FileUtil.ReadFileLineContent(buildingsObject.BuildingsFilePath, delegate (string readerLineContent)
            {
                if (string.IsNullOrEmpty(readerLineContent) == false)
                {
                    string[] readerLineArray = IteratorUtil.Trim(readerLineContent.Split(new char[] { ' ' }));

                    if (readerLineArray.Length == 3)
                    {
                        if (cusor > 1)
                        {
                            buildingVectorObjects.Add(buildVectorObject.OID, buildVectorObject);
                        }

                        buildVectorObject = new BuildingVectorObject()
                        {
                            OID = tempOrderOID,
                            Index = Convert.ToInt32(readerLineArray[0]),
                            VectorPointCount = Convert.ToInt32(readerLineArray[2])
                        };

                        tempOrderOID++;
                    }
                    else if (readerLineArray.Length == 2)
                    {
                        double longitude = double.Parse(readerLineArray[0]);
                        double latitude = double.Parse(readerLineArray[1]);

                        double x = 0, y = 0;
                        

                        using (SuperMap.Data.GeoPoint point = new SuperMap.Data.GeoPoint(Convert.ToDouble(longitude), Convert.ToDouble(latitude)))
                        {
                            CoordSysTranslatorHandler.ConvertCoordSys(point, MapPrjCoordSys, LatLonPrjCoordSys);
                            MecatorUtil.loc_to_mercator(point.X, point.Y, ref x, ref y);

                            longitude = x;
                            latitude = y;
                        }
                        
                        buildVectorObject.VectorPoints.Add(new VectorPoint()
                        {
                            longitude = longitude,
                            Latitude = latitude,
                            Relativelongitude = double.Parse((longitude - totalBuildingsObject.MinX).ToString("0.0000")),
                            RelativeLatitude = double.Parse((latitude - totalBuildingsObject.MinY).ToString("0.0000"))
                        });
                    }

                    int currentProgressValue = Convert.ToInt32(cusor * 100 / rowCount);
                    if (currentProgressValue > prevProgressValue)
                    {
                        prevProgressValue = currentProgressValue;
                        //this.backgroundWorker1.ReportProgress(currentProgressValue, string.Format("正在读取{0}文件...", DTGroup.Networking.Framework.Utils.IOUtil.GetFileName(buildingsObject.BuildingsFilePath)));
                    }

                    cusor++;
                }
            });

            if (buildingVectorObjects.Count > 0)
            {
                ReadBuildingsAttribute(buildingVectorObjects, buildingsObject, orderOID);
            }

            return tempOrderOID;
        }

        private void ReadBuildingsAttribute(Dictionary<int, BuildingVectorObject> buildingVectorObjects, BuildingsObject buildingsObject, int orderOID)
        {
            int rowCount = 0;
            // 读取 文件的行数
            FileUtil.ReadFileLineContent(buildingsObject.BuildingsAttributeFilePath, delegate (string readerLineContent)
            {
                if (string.IsNullOrEmpty(readerLineContent) == false)
                {
                    rowCount++;
                }
            });

            int cusor = 1;
            int prevProgressValue = 0;
            // 读取 Index 文件内容
            FileUtil.ReadFileLineContent(buildingsObject.BuildingsAttributeFilePath, delegate (string readerLineContent)
            {
                if (string.IsNullOrEmpty(readerLineContent) == false)
                {
                    string[] readerLineArray = IteratorUtil.Trim(readerLineContent.Split(new char[] { ' ' }));

                    if (readerLineArray.Length == 3)
                    {
                        if (buildingVectorObjects.Keys.Contains(orderOID))
                        {
                            BuildingVectorObject buildVector = buildingVectorObjects[orderOID];
                            // 设置建筑物高度
                            buildVector.Height = double.Parse(readerLineArray[2]);
                        }
                    }

                    int currentProgressValue = Convert.ToInt32(cusor * 100 / rowCount);
                    if (currentProgressValue > prevProgressValue)
                    {
                        prevProgressValue = currentProgressValue;
                        //this.ReportProgress(currentProgressValue, string.Format("正在读取{0}文件...", IOUtil.GetFileName(buildingsObject.BuildingsAttributeFilePath)), TaskStatus.Running);
                    }
                    orderOID++;
                    cusor++;
                }
            });
        }

        private void OutODAFilePath(Dictionary<int, BuildingVectorObject> buildingVectorObjects, string outFilePath, BuildingsObject buildingsObject)
        {
            if (File.Exists(outFilePath))
            {
                File.Delete(outFilePath);
            }
            int prevProgressValue = 0;
            int cusor = 1;

            using (StreamWriter write = new StreamWriter(outFilePath, true, Encoding.ASCII))
            {
                // Database generated by WallMan  -  Thursday, April 15, 2010  -  15:48:53  
                write.WriteLine("Database generated by WallMan " + DateTime.Now.Year.ToString(), "  -  ", DateTime.Now.ToString("HH:MM:SS"));
                write.WriteLine("Size of the area: ");
                double relativeLongitude = double.Parse((buildingsObject.MaxX - buildingsObject.MinX).ToString("0.0000"));
                double relativeLatitude = double.Parse((buildingsObject.MaxY - buildingsObject.MinY).ToString("0.0000"));
                write.WriteLine("  Max.x=" + relativeLongitude);
                write.WriteLine("  Max.y=" + relativeLatitude);
                write.WriteLine("This line is intentionally left blank");
                write.WriteLine(string.Format("{0} {1} {2} {3} {4} {5}", buildingVectorObjects.Count, Convert.ToInt32(buildingsObject.MinX), Convert.ToInt32(buildingsObject.MinY), relativeLongitude, relativeLatitude, "WINPROP"));
                foreach (KeyValuePair<int, BuildingVectorObject> item in buildingVectorObjects)
                {
                    if (item.Value.VectorPointCount > 0)
                    {
                        StringBuilder strBuilder = new StringBuilder(item.Value.OID + " " + item.Value.VectorPointCount + "    ");

                        foreach (VectorPoint point in item.Value.VectorPoints)
                        {
                            strBuilder.Append(point.Relativelongitude + "," + point.RelativeLatitude + "    ");
                        }
                        strBuilder.Append(item.Value.Height + " 1 0");
                        write.WriteLine(strBuilder);
                        strBuilder = null;
                    }

                    int currentProgressValue = Convert.ToInt32(cusor * 100 / buildingVectorObjects.Count);
                    if (currentProgressValue > prevProgressValue)
                    {
                        prevProgressValue = currentProgressValue;
                        //this.ReportProgress(currentProgressValue, string.Format("正在生成{0}文件...", outFilePath), TaskStatus.Running);
                    }

                    cusor++;
                }
            };
        }

        private string GetMapODAFilePath(string odaDirectory)
        {
            return Path.Combine(odaDirectory, "BuildingVector.ODA");
        }

        /// <summary>
        /// 地图坐标投影
        /// </summary>
        public static PrjCoordSys LatLonPrjCoordSys
        {
            get
            {
                // 设置经纬度投影
                PrjCoordSys prjCoordSys = new PrjCoordSys();
                prjCoordSys.Type = PrjCoordSysType.EarthLongitudeLatitude;
                prjCoordSys.GeoCoordSys.Type = SuperMap.Data.GeoCoordSysType.Wgs1984;
                return prjCoordSys;
            }
        }

        /// <summary>
        /// 摩卡托投影
        /// </summary>
        public static PrjCoordSys MercatorPrjCoordSys
        {
            get
            {
                // 设置经纬度投影
                PrjCoordSys prjCoordSys = new PrjCoordSys();
                prjCoordSys.Type = PrjCoordSysType.UserDefined;
                // 设置地理坐标系
                prjCoordSys.GeoCoordSys.Type = SuperMap.Data.GeoCoordSysType.UserDefined;
                // 投影类型
                prjCoordSys.Projection.Type = SuperMap.Data.ProjectionType.SphereMercator;

                return prjCoordSys;
            }
        }

        private PrjCoordSys mapPrjCoordSys;
        public PrjCoordSys MapPrjCoordSys
        {
            get
            {
                return mapPrjCoordSys;
            }
        }

        private Dictionary<string, List<string>> LoadIndoorGrid(int p_city) {
            string indoorGridFile = System.AppDomain.CurrentDomain.BaseDirectory + "\\gridmappingbuilding\\" + p_city + ".csv";
            Dictionary<string, List<string>> dicGrid = new Dictionary<string, List<string>>();
            
            using (StreamReader sr = new StreamReader(indoorGridFile))
            {
                string line = sr.ReadLine();

                do
                {
                    var arr = line.Split(',');
                    if (dicGrid.ContainsKey(arr[0]))
                    {
                        dicGrid[arr[0]].Add(arr[1]);
                    }
                    else {
                        dicGrid.Add(arr[0], new List<string> { arr[1] });
                    }
                    
                    line = sr.ReadLine();
                } while (!string.IsNullOrEmpty(line));
            }

            return dicGrid;
        }
    }
}
